package com.gitee.huanminabc.dynamicdb.core;

import com.gitee.huanminabc.dynamicdb.common.DBSupplierEx;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;

/**
 * @author huanmin
 * @date 2024/11/22
 */
@Slf4j
public class DBSwatch {

    // 非外部使用
    // 手动切换数据源,此方法必须在线程创建的源头处使用, 这样在进入线程池的时候记录就会+1,
    //那么线程内部的操作都不会把线程的数据清除, 只有线程池结束的时候才会清除
    //runnable 作用就是将创建线程的哪个动作放到这里执行
    //比如可以在AOP 或者web拦截器, 过滤器 , 线程池创建线程的时候调用此方法 ,再次提示必须在源头位置调用
    public static <T> T threadDb(String dbKey, DBSupplierEx<T> runnable) throws Throwable {
        if (Strings.isEmpty(dbKey)) {
            return runnable.get();
        }
        //记录之前的数据源
        String oldDbKey = DbKeysManage.currentDbKey();
        //如果新旧数据源一样,则不需要切换
        if (dbKey.equals(oldDbKey)) {
            return runnable.get();
        }
        log.info("切换数据源: oldDbKey={}, newDbKey={}", oldDbKey, dbKey);
        try {
            //切换为指定数据库
            DbKeysManage.switchDbKey(dbKey);
            //事务添加,因为可能之前已经开启了事务,这里就需要加入他的事务管理器或者新建事务管理器,无论是否子有没有开启事务,都需要有事务管理
            //因为当子方法执行完毕后,走回主了, 然后主失败了,那么子之前的操作是不是也要回滚
            if ( TransactionalManage.hasTransaction()) {
                return DBSwatchUtil.muchTransactional(runnable);
            }
            //执行业务方法
            return runnable.get();
        } finally {
            //还原为默认配置
            DbKeysManage.switchDbKey(oldDbKey);
            //不用清除线程数据,因为自定义的线程池会清除, 或者拦截器会清除
        }
    }
}
